#pragma once
#include <iostream>
#include <cstdio>
#include <ctime>
#include <memory>
#include <sstream>
#include <chrono>
#include <random>
#include <atomic>
#include <iomanip>
#include "jsoncpp/json/json.h"

// 设置等级 打印不同等级的日志
#define DEBUGLEVEL 0
#define INFOLEVEL 1
#define ERRORLEVEL 2
#define DEFAULTLEVEL DEBUGLEVEL

namespace MyRpc
{
    // 日志部分
    // C语言提供的可变参数模板 
    // 这个##__VA_ARGS__ 代表了可变参数的实体
    #define LOG(level, format, ...) {\
        if(level >= DEFAULTLEVEL)\
        {\
            time_t t = time(NULL);\
            struct tm* cur = localtime(&t);\
            printf("[%s:%d] " "[%d-%d-%d %d:%d:%d] --> " format "\n", __FILE__, __LINE__, cur->tm_year + 1900, cur->tm_mon + 1, cur->tm_mday\
                , cur->tm_hour, cur->tm_min, cur->tm_sec, ##__VA_ARGS__);\
        }\     
    }

    class JSON
    {
    public:
        // json 部分 序列化 反序列化
        static bool serialize(Json::Value& root, std::string& body)
        {
            // 这个StreamWriterBuilder是StreamWriter的子类对象
            Json::StreamWriterBuilder swb;
            // 因为StreamWriter是抽象类 不可以直接实例化出对象 所以用基类指针指向子类函数 多态
            std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());
            std::stringstream ss;
            int ret = sw->write(root, &ss);
            if(ret != 0)
            {
                std::cout << "serialize failed!" << std::endl;
                return false;
            }
            body = ss.str();
            return true;
        }

        static bool deserialize(const std::string& body, Json::Value& root)
        {
            // 这个CharReaderBuilder是CharReader的子类对象
            Json::CharReaderBuilder crb;
            // 因为CharReader是抽象类对象 不能实例化出对象 所以用基类指针指向子类对象
            std::unique_ptr<Json::CharReader> cr(crb.newCharReader());
            
            std::string serr;
            int ret = cr->parse(body.c_str(), body.c_str() + body.size(), &root, &serr);
            if(ret == 0)
            {
                std::cout << "deserialize failed!" << std::endl;
                return false;
            }
            return true;
        }
    };

    class UUID
    {
    public:
        static std::string uuid()
        {
            std::stringstream ss; 
            // 先生成一个机器随机码 这个是唯一的一个值 当作随机数种子 但是机器码产生的随机数比较慢
            std::random_device rd;
            // 生成随机数的函数 导入随机数种子
            std::mt19937 g1(rd());
            // 控制随机数的大小为8字节的数据 这里控制一个16进制的数据为 0-15
            std::uniform_int_distribution<unsigned int> distribution(0, 0xFF);  // 这里定义的是无符号整型类型 所以大小为 0-0xFF
            for(int i = 0; i < 8; i++)
            {
                // 先产生一个字节的数据
                unsigned int num = distribution(g1);
                // std::cout << num << "\n";
                char buffer[1024];
                int n = snprintf(buffer, sizeof(buffer) - 1, "%.2x", num);
                buffer[n] = 0;
                // std::cout << buffer << "\n";
                if(i == 4 || i == 6)
                    ss << '-';
                ss << buffer;
            }
            ss << '-';
            // //5. 定义⼀个8字节序号， 也就是8 * 8 = 64 bit位，逐字节组织成为16进制数字字符的字符串 从1开始
            static std::atomic<size_t> seq(1);
            size_t cur = seq.fetch_add(1);  // 代表每次计数 +1 
            for (int i = 7; i >= 0; i--) 
            {
                if (i == 5) ss << "-";
                // 首先设置宽度为 2  不足用 0 补全  然后输出格式是 hex 也就是16进制
                ss << std::setw(2) << std::setfill('0') << std::hex << ((cur >> (i*8)) & 0xFF);  
                //                                              每次拿出一个字节的数据进行按位 & 然后再转化为16进制
            } 
            // std::cout << ss.str() << "\n";
            return ss.str();
        }
    };


}